﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Security;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Owin;
using System.Security;
using Microsoft.SharePoint.Client;
using CloudStorageLight.Core;
using CloudStorageLight.Core.Web;

namespace CloudStorageLight.SharePointWeb.Models
{
    public static class BasicAuthenticateUtil
    {
        #pragma warning disable 1998
        public async static Task Authenticate(HttpApplication httpApp)
        {
            string authString = httpApp.Request.Headers["Authorization"];
            string clientToken = httpApp.Request.Headers["ClientToken"];

            if (!string.IsNullOrEmpty(authString) && authString.IndexOf("Basic", 0) == 0)
            {
                string encodedString = authString.Substring(6);
                byte[] decodedBytes = Convert.FromBase64String(encodedString);
                string decodedString = new ASCIIEncoding().GetString(decodedBytes);
                string[] arrSplited = decodedString.Split(new char[] { ':' });
                string username = arrSplited[0];
                string password = arrSplited[1];
                if (AuthenticateUser(username, password, clientToken))
                {
                    if (string.IsNullOrEmpty(clientToken))
                    {
                        var ctoken = new ClientToken { ExpireDate = DateTime.MaxValue, IsuueDate = DateTime.UtcNow, InitIPAddress = WebUtil.GetIPAddress(), UserName = username };
                        httpApp.Response.Headers.Add("ClientToken", ctoken.ToToken());
                    }
                }
                else
                {
                    httpApp.Response.Clear();
                    httpApp.Response.StatusCode = 401;
                    httpApp.Response.StatusDescription = "Unauthorized";
                    httpApp.Response.Write("<html><head><title>401 Unauthorized</title></head><body><h1>401 Access Denied</h1></body></html>");
                }
            }
        }
        #pragma warning restore 1998

        public static void AddUnauthorizedHeader(HttpApplication httpApp)
        {
            httpApp.Response.AppendHeader("WWW-Authenticate", "Basic Realm=Authentication");
        }

        /// <summary>
        /// ユーザ名パスワードで認証
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <param name="clientToken"></param>
        /// <param name="cloudAccount"></param>
        /// <returns></returns>
        public static bool AuthenticateUser(string username, string password, string clientToken, CloudAccount cloudAccount = null)
        {
            var securePassword = new SecureString();
            foreach (char c in password)
            {
                securePassword.AppendChar(c);
            }
            var onlineCredentials = new SharePointOnlineCredentials(username, securePassword);

            cloudAccount = cloudAccount ?? BlobService.GetCurrentCloudAccount();
            if (cloudAccount == null) return false;
            using (var ctx = new ClientContext(cloudAccount.SpHostUrl))
            {
                ctx.Credentials = onlineCredentials;
                try
                {
                    var spUser = ctx.Web.CurrentUser;
                    ctx.Load(spUser, user => user.Email, user => user.Groups);
                    ctx.ExecuteQuery();

                    if (cloudAccount.UseClientTokenForIPCheck && !string.IsNullOrEmpty(clientToken))
                    {
                        var clientTokenTicket = ClientToken.Parse(clientToken);
                        if (clientTokenTicket == null || !cloudAccount.CanAccessIPAddress(clientTokenTicket.InitIPAddress))
                        {
                            if (!cloudAccount.CanAccessIPAddress(WebUtil.GetIPAddress()))
                            {
                                throw new BlobException(BlobExceptionCode.InvalidIPAddress);
                            }
                            clientToken = null;
                        }
                    }
                    else
                    {
                        if (!cloudAccount.CanAccessIPAddress(WebUtil.GetIPAddress()))
                        {
                            throw new BlobException(BlobExceptionCode.InvalidIPAddress);
                        }

                    }

                    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0, spUser.Email, DateTime.UtcNow, DateTime.UtcNow.AddMinutes(cloudAccount.AuthTicketTimeout.Value), false, cloudAccount.AccountName);
                    HttpCookie cookie = new HttpCookie(
                        FormsAuthentication.FormsCookieName,
                        FormsAuthentication.Encrypt(ticket));

                    System.Web.HttpContext.Current.Response.Cookies.Add(cookie);
                    System.Web.HttpContext.Current.User = new GenericPrincipal(new GenericIdentity(spUser.Email), spUser.Groups.Select(x => x.Title).ToArray());

                    AttachedSharePointBlobAdapter.SetSpsClientContext(ctx);

                    return true;
                }
                catch (Exception ex)
                {
                    var log = new LogService(SystemSettings.Instance.BlobStorage);
                    log.EntryLog(username, cloudAccount.AccountName??"", "AuthenticateUser", "", ex.ToString());
                    return false;
                }
            }
 
        }

        /// <summary>
        /// 現在ユーザ取得
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        /// <remarks>
        /// SharePointユーザまたはCookieによる認証が行われていればOK
        /// </remarks>
        public static BlobUser GetCurrentUser(CloudAccount account = null)
        {
            BlobUser user;
            var authCookie = System.Web.HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

            // If it exists then decrypt and setup the generic principal
            if (authCookie != null && !string.IsNullOrEmpty(authCookie.Value))
            {
                var ticket = FormsAuthentication.Decrypt(authCookie.Value);
                var currentDomain = account == null ? BlobService.GetCurrentDomain() : account.AccountName;
                if (currentDomain != ticket.UserData) throw new BlobException(BlobExceptionCode.NotAuthorization);
            }
            user = new AppBlobUser(System.Web.HttpContext.Current.User);

            return user;

        }
    }

}